import BuiltinExtension
import ChatGPTChatTab
import ChatService
import ChatTab
import Foundation
import PromptToCodeService
import SuggestionBasic
import SuggestionWidget
import XcodeInspector

#if canImport(ProChatTabs)
import ProChatTabs
#endif

enum ChatTabFactory {
    static func chatTabBuilderCollection() -> [ChatTabBuilderCollection] {
        #if canImport(ProChatTabs)
        _ = lazyLoadDependency
        let collection = [
            folderIfNeeded(ChatGPTChatTab.chatBuilders(), title: ChatGPTChatTab.name),
            folderIfNeeded(BrowserChatTab.chatBuilders(), title: BrowserChatTab.name),
            folderIfNeeded(TerminalChatTab.chatBuilders(), title: TerminalChatTab.name),
        ]
        #else
        let collection = [
            folderIfNeeded(ChatGPTChatTab.chatBuilders(), title: ChatGPTChatTab.name),
        ]
        #endif

        return chatTabsFromExtensions()
    }

    private static func folderIfNeeded(
        _ builders: [any ChatTabBuilder],
        title: String
    ) -> ChatTabBuilderCollection? {
        if builders.count > 1 {
            return .folder(title: title, kinds: builders.map(ChatTabKind.init))
        }
        if let first = builders.first { return .kind(ChatTabKind(first)) }
        return nil
    }

    static func chatTabsFromExtensions() -> [ChatTabBuilderCollection] {
        let extensions = BuiltinExtensionManager.shared.extensions
        let chatTabTypes = extensions
            .filter { $0.extensionIdentifier == "com.codeium" }
            .flatMap(\.chatTabTypes)
        return chatTabTypes.compactMap { folderIfNeeded($0.chatBuilders(), title: $0.name) }
    }
}

#if canImport(ProChatTabs)
let lazyLoadDependency: () = {
    BrowserChatTab.externalDependency = .init(
        handleCustomCommand: { command, prompt in
            switch command.feature {
            case let .chatWithSelection(extraSystemPrompt, _, useExtraSystemPrompt):
                let service = ChatService()
                return try await service.processMessage(
                    systemPrompt: nil,
                    extraSystemPrompt: (useExtraSystemPrompt ?? false) ? extraSystemPrompt :
                        nil,
                    prompt: prompt
                )
            case let .customChat(systemPrompt, _):
                let service = ChatService()
                return try await service.processMessage(
                    systemPrompt: systemPrompt,
                    extraSystemPrompt: nil,
                    prompt: prompt
                )
            case let .singleRoundDialog(
                systemPrompt,
                overwriteSystemPrompt,
                _,
                _
            ):
                let service = ChatService()
                return try await service.handleSingleRoundDialogCommand(
                    systemPrompt: systemPrompt,
                    overwriteSystemPrompt: overwriteSystemPrompt ?? false,
                    prompt: prompt
                )
            case let .promptToCode(extraSystemPrompt, instruction, _, _):
                let service = OpenAIPromptToCodeService()

                let result = try await service.modifyCode(
                    code: prompt,
                    requirement: instruction ?? "Modify content.",
                    source: .init(
                        language: .plaintext,
                        documentURL: .init(fileURLWithPath: "/"),
                        projectRootURL: .init(fileURLWithPath: "/"),
                        content: prompt,
                        lines: prompt.breakLines(),
                        range: .outOfScope
                    ),
                    isDetached: true,
                    extraSystemPrompt: extraSystemPrompt,
                    generateDescriptionRequirement: false
                )
                var code = ""
                for try await (newCode, _) in result {
                    code = newCode
                }
                return code
            }
        }
    )
}()
#endif

